﻿namespace WorldView
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;

    public class WorldMapper
    {
        // It should be Tiletype enum but my hand hurts too much to fix.
        public static Dictionary<int, TileProperties> tileTypeDefs;
        public static Color[] colorTypeDefs = new Color[300];

        private Dictionary<TileType, List<Point>> tilesToSymbolize;

        private WorldHeader worldHeader;
        private WorldReader reader;

        private BinaryWriter writer;

        public WorldMapper()
        {
            tileTypeDefs = new Dictionary<int, TileProperties>(255);

        }

        public WorldHeader Header
        {
            get
            {
                return this.worldHeader;
            }
        }

        /// <summary>
        /// Intiialize and load tile types
        /// </summary>
        public void Initialize()
        {
            // :OHGOD:
            tileTypeDefs[0] = new TileProperties(TileType.Dirt, false, Constants.Colors.DIRT);
            tileTypeDefs[1] = new TileProperties(TileType.Stone, false, Constants.Colors.STONE);
            tileTypeDefs[2] = new TileProperties(TileType.Grass, false, Constants.Colors.GRASS);
            tileTypeDefs[3] = new TileProperties(TileType.Plants, true, Constants.Colors.PLANTS);
            tileTypeDefs[4] = new TileProperties(TileType.Torches, false, Constants.Colors.LIGHT_SOURCE);
            tileTypeDefs[5] = new TileProperties(TileType.Trees, true, Constants.Colors.TREE);
            tileTypeDefs[6] = new TileProperties(TileType.Iron, false, Constants.Colors.IRON);
            tileTypeDefs[7] = new TileProperties(TileType.Copper, false, Constants.Colors.COPPER);
            tileTypeDefs[8] = new TileProperties(TileType.Gold, false, Constants.Colors.GOLD);
            tileTypeDefs[9] = new TileProperties(TileType.Silver, false, Constants.Colors.SILVER);

            tileTypeDefs[10] = new TileProperties(TileType.Door1, true, Constants.Colors.DOOR1);
            tileTypeDefs[11] = new TileProperties(TileType.Door2, true, Constants.Colors.DOOR2);
            tileTypeDefs[12] = new TileProperties(TileType.HeartStone, true, Constants.Colors.HEART, new Symbol("heart.png"));
            tileTypeDefs[13] = new TileProperties(TileType.Bottles, true, Constants.Colors.BOTTLE);
            tileTypeDefs[14] = new TileProperties(TileType.Table, true, Constants.Colors.TABLE);
            tileTypeDefs[15] = new TileProperties(TileType.Chair, true, Constants.Colors.CHAIR);
            tileTypeDefs[16] = new TileProperties(TileType.Anvil, true, Constants.Colors.ANVIL);
            tileTypeDefs[17] = new TileProperties(TileType.Furnance, true, Constants.Colors.FURNACE);
            tileTypeDefs[18] = new TileProperties(TileType.CraftingTable, true, Constants.Colors.CTABLE);
            tileTypeDefs[19] = new TileProperties(TileType.WoodenPlatform, false, Constants.Colors.WOODP);
            tileTypeDefs[20] = new TileProperties(TileType.PlantsDecorative, true, Constants.Colors.PLANTS);

            tileTypeDefs[21] = new TileProperties(TileType.Chest, true, Constants.Colors.CHEST, new Symbol("chest.png"));
            tileTypeDefs[22] = new TileProperties(TileType.CorruptionStone1, false, Constants.Colors.CORRUPTION_STONE);
            tileTypeDefs[23] = new TileProperties(TileType.CorruptionGrass, false, Constants.Colors.CORRUPTION_GRASS);
            tileTypeDefs[24] = new TileProperties(TileType.CorruptionPlants, true, Constants.Colors.CORRUPTION_GRASS);
            tileTypeDefs[25] = new TileProperties(TileType.CorruptionStone2, false, Constants.Colors.CORRUPTION_STONE2);
            tileTypeDefs[26] = new TileProperties(TileType.Altar, true, Constants.Colors.ALTAR, new Symbol("altar.png"));
            tileTypeDefs[27] = new TileProperties(TileType.Sunflower, true, Constants.Colors.SUNF);
            tileTypeDefs[28] = new TileProperties(TileType.Pot, true, Constants.Colors.POT);
            tileTypeDefs[29] = new TileProperties(TileType.PiggyBank, true, Constants.Colors.PBANK);
            tileTypeDefs[30] = new TileProperties(TileType.BlockWood, false, Constants.Colors.BLOCKW);

            tileTypeDefs[31] = new TileProperties(TileType.ShadowOrb, true, Constants.Colors.SORB, new Symbol("shadow.png"));
            tileTypeDefs[32] = new TileProperties(TileType.CorruptionVines, false, Constants.Colors.CORRUPTION_VINES);
            tileTypeDefs[33] = new TileProperties(TileType.Candle, true, Constants.Colors.CANDLE);
            tileTypeDefs[34] = new TileProperties(TileType.ChandlerCopper, true, Constants.Colors.CHC);
            tileTypeDefs[35] = new TileProperties(TileType.ChandlerSilver, true, Constants.Colors.CHS);
            tileTypeDefs[36] = new TileProperties(TileType.ChandlerGold, true, Constants.Colors.CHG);
            tileTypeDefs[37] = new TileProperties(TileType.Meterorite, false, Constants.Colors.METEORITE);
            tileTypeDefs[38] = new TileProperties(TileType.BlockStone, false, Constants.Colors.BLOCK_S);
            tileTypeDefs[39] = new TileProperties(TileType.BlockRedStone, false, Constants.Colors.BLOCKRS);
            tileTypeDefs[40] = new TileProperties(TileType.Clay, false, Constants.Colors.CLAY);

            tileTypeDefs[41] = new TileProperties(TileType.BlockBlueStone, false, Constants.Colors.DUNGEONB);
            tileTypeDefs[42] = new TileProperties(TileType.LightGlobe, true, Constants.Colors.LIGHTGL);
            tileTypeDefs[43] = new TileProperties(TileType.BlockGreenStone, false, Constants.Colors.DUNGEONG);
            tileTypeDefs[44] = new TileProperties(TileType.BlockPinkStone, false, Constants.Colors.DUNGEONP);
            tileTypeDefs[45] = new TileProperties(TileType.BlockGold, false, Constants.Colors.BLOCKGO);
            tileTypeDefs[46] = new TileProperties(TileType.BlockSilver, false, Constants.Colors.BLOCKSI);
            tileTypeDefs[47] = new TileProperties(TileType.BlockCopper, false, Constants.Colors.BLOCKCO);
            tileTypeDefs[48] = new TileProperties(TileType.Spikes, false, Constants.Colors.SPIKES);
            tileTypeDefs[49] = new TileProperties(TileType.CandleBlue, false, Constants.Colors.CANDLEB);
            tileTypeDefs[50] = new TileProperties(TileType.Books, true, Constants.Colors.BOOK);

            tileTypeDefs[51] = new TileProperties(TileType.Web, false, Constants.Colors.WEB);
            tileTypeDefs[52] = new TileProperties(TileType.Vines, false, Constants.Colors.VINE);
            tileTypeDefs[53] = new TileProperties(TileType.Sand, false, Constants.Colors.SAND);
            tileTypeDefs[54] = new TileProperties(TileType.Glass, false, Constants.Colors.GLASS);
            tileTypeDefs[55] = new TileProperties(TileType.Signs, true, Constants.Colors.SIGN);
            tileTypeDefs[56] = new TileProperties(TileType.Obsidian, false, Constants.Colors.OBSIDIAN);
            tileTypeDefs[57] = new TileProperties(TileType.Ash, false, Constants.Colors.ASH);
            tileTypeDefs[58] = new TileProperties(TileType.Hellstone, false, Constants.Colors.HELLSTONE);
            tileTypeDefs[59] = new TileProperties(TileType.Mud, false, Constants.Colors.MUD);
            tileTypeDefs[60] = new TileProperties(TileType.UndergroundJungleGrass, false, Constants.Colors.UNDERGROUNDJUNGLE_GRASS);

            tileTypeDefs[61] = new TileProperties(TileType.UndergroundJunglePlants, true, Constants.Colors.UNDERGROUNDJUNGLE_PLANTS);
            tileTypeDefs[62] = new TileProperties(TileType.UndergroundJungleVines, false, Constants.Colors.UNDERGROUNDJUNGLE_VINES);
            tileTypeDefs[63] = new TileProperties(TileType.GemSapphire, false, Constants.Colors.GEMS_S, new Symbol("gem_s.png"));
            tileTypeDefs[64] = new TileProperties(TileType.GemRuby, false, Constants.Colors.GEMS_R, new Symbol("gem_r.png"));
            tileTypeDefs[65] = new TileProperties(TileType.GemEmerald, false, Constants.Colors.GEMS_E, new Symbol("gem_e.png"));
            tileTypeDefs[66] = new TileProperties(TileType.GemTopaz, false, Constants.Colors.GEMS_T, new Symbol("gem_t.png"));
            tileTypeDefs[67] = new TileProperties(TileType.GemAmethyst, false, Constants.Colors.GEMS_A, new Symbol("gem_a.png"));
            tileTypeDefs[68] = new TileProperties(TileType.GemDiamond, false, Constants.Colors.GEMS_D, new Symbol("gem_d.png"));
            tileTypeDefs[69] = new TileProperties(TileType.UndergroundJungleThorns, false, Constants.Colors.UNDERGROUNDJUNGLE_THORNS);
            tileTypeDefs[70] = new TileProperties(TileType.UndergroundMushroomGrass, false, Constants.Colors.UNDERGROUNDMUSHROOM_GRASS);

            tileTypeDefs[71] = new TileProperties(TileType.UndergroundMushroomPlants, true, Constants.Colors.UNDERGROUNDMUSHROOM_PLANTS);
            tileTypeDefs[72] = new TileProperties(TileType.UndergroundMushroomTrees, true, Constants.Colors.UNDERGROUNDMUSHROOM_TREES);
            tileTypeDefs[73] = new TileProperties(TileType.Plants2, true, Constants.Colors.PLANTS);
            tileTypeDefs[74] = new TileProperties(TileType.Plants3, true, Constants.Colors.PLANTS);
            tileTypeDefs[75] = new TileProperties(TileType.BlockObsidian, false, Constants.Colors.BLOCKOB);
            tileTypeDefs[76] = new TileProperties(TileType.BlockHellstone, false, Constants.Colors.BLOCKHS);
            tileTypeDefs[77] = new TileProperties(TileType.UnderworldFurnance, true, Constants.Colors.UFURNACE);
            tileTypeDefs[78] = new TileProperties(TileType.DecorativePot, true, Constants.Colors.DPOT);
            tileTypeDefs[79] = new TileProperties(TileType.Bed, true, Constants.Colors.BED);
            tileTypeDefs[80] = new TileProperties(TileType.Unknown, false, Constants.Colors.UNKNOWN);

            for (int i = 80; i < 255; i++)
            {
                tileTypeDefs[i] = new TileProperties(TileType.Unknown, false, Color.Magenta);
            }

            tileTypeDefs[256] = new TileProperties(TileType.Sky, false, Constants.Colors.SKY);
            tileTypeDefs[257] = new TileProperties(TileType.Water, false, Constants.Colors.WATER);
            tileTypeDefs[258] = new TileProperties(TileType.Lava, false, Constants.Colors.LAVA);

            // Walls
            tileTypeDefs[259] = new TileProperties(TileType.WallStone, false, Constants.Colors.WALL_STONE);
            tileTypeDefs[260] = new TileProperties(TileType.WallDirt, false, Constants.Colors.WALL_DIRT);
            tileTypeDefs[261] = new TileProperties(TileType.WallStone2, false, Constants.Colors.WALL_STONE2);
            tileTypeDefs[262] = new TileProperties(TileType.WallWood, false, Constants.Colors.WALL_WOOD);
            tileTypeDefs[263] = new TileProperties(TileType.WallBrick, false, Constants.Colors.WALL_BRICK);
            tileTypeDefs[264] = new TileProperties(TileType.WallRed, false, Constants.Colors.WALL_BRICKR);
            tileTypeDefs[265] = new TileProperties(TileType.WallBlue, false, Constants.Colors.WALL_BRICKB);
            tileTypeDefs[266] = new TileProperties(TileType.WallGreen, false, Constants.Colors.WALL_BRICKG);
            tileTypeDefs[267] = new TileProperties(TileType.WallPink, false, Constants.Colors.WALL_BRICKP);
            tileTypeDefs[268] = new TileProperties(TileType.WallGold, false, Constants.Colors.WALL_BRICKGO);
            tileTypeDefs[269] = new TileProperties(TileType.WallSilver, false, Constants.Colors.WALL_BRICKS);
            tileTypeDefs[270] = new TileProperties(TileType.WallCopper, false, Constants.Colors.WALL_BRICKC);
            tileTypeDefs[271] = new TileProperties(TileType.WallHellstone, false, Constants.Colors.WALL_BRICKHS);
            tileTypeDefs[272] = new TileProperties(TileType.WallHellstone, false, Constants.Colors.WALL_BACKGROUND);

            //color defs
            colorTypeDefs[0] = (Constants.Colors.DIRT);
            colorTypeDefs[1] = (Constants.Colors.STONE);
            colorTypeDefs[2] = (Constants.Colors.GRASS);
            colorTypeDefs[3] = (Constants.Colors.PLANTS);
            colorTypeDefs[4] = (Constants.Colors.LIGHT_SOURCE);
            colorTypeDefs[5] = (Constants.Colors.TREE);
            colorTypeDefs[6] = (Constants.Colors.IRON);
            colorTypeDefs[7] = (Constants.Colors.COPPER);
            colorTypeDefs[8] = (Constants.Colors.GOLD);
            colorTypeDefs[9] = (Constants.Colors.SILVER);

            colorTypeDefs[10] = (Constants.Colors.DOOR1);
            colorTypeDefs[11] = (Constants.Colors.DOOR2);
            colorTypeDefs[12] = (Constants.Colors.HEART);
            colorTypeDefs[13] = (Constants.Colors.BOTTLE);
            colorTypeDefs[14] = (Constants.Colors.TABLE);
            colorTypeDefs[15] = (Constants.Colors.CHAIR);
            colorTypeDefs[16] = (Constants.Colors.ANVIL);
            colorTypeDefs[17] = (Constants.Colors.FURNACE);
            colorTypeDefs[18] = (Constants.Colors.CTABLE);
            colorTypeDefs[19] = (Constants.Colors.WOODP);
            colorTypeDefs[20] = (Constants.Colors.PLANTS);

            colorTypeDefs[21] = (Constants.Colors.CHEST);
            colorTypeDefs[22] = (Constants.Colors.CORRUPTION_STONE);
            colorTypeDefs[23] = (Constants.Colors.CORRUPTION_GRASS);
            colorTypeDefs[24] = (Constants.Colors.CORRUPTION_GRASS);
            colorTypeDefs[25] = (Constants.Colors.CORRUPTION_STONE2);
            colorTypeDefs[26] = (Constants.Colors.ALTAR);
            colorTypeDefs[27] = (Constants.Colors.SUNF);
            colorTypeDefs[28] = (Constants.Colors.POT);
            colorTypeDefs[29] = (Constants.Colors.PBANK);
            colorTypeDefs[30] = (Constants.Colors.BLOCKW);

            colorTypeDefs[31] = (Constants.Colors.SORB);
            colorTypeDefs[32] = (Constants.Colors.CORRUPTION_VINES);
            colorTypeDefs[33] = (Constants.Colors.CANDLE);
            colorTypeDefs[34] = (Constants.Colors.CHC);
            colorTypeDefs[35] = (Constants.Colors.CHS);
            colorTypeDefs[36] = (Constants.Colors.CHG);
            colorTypeDefs[37] = (Constants.Colors.METEORITE);
            colorTypeDefs[38] = (Constants.Colors.BLOCK_S);
            colorTypeDefs[39] = (Constants.Colors.BLOCKRS);
            colorTypeDefs[40] = (Constants.Colors.CLAY);

            colorTypeDefs[41] = (Constants.Colors.DUNGEONB);
            colorTypeDefs[42] = (Constants.Colors.LIGHTGL);
            colorTypeDefs[43] = (Constants.Colors.DUNGEONG);
            colorTypeDefs[44] = (Constants.Colors.DUNGEONP);
            colorTypeDefs[45] = (Constants.Colors.BLOCKGO);
            colorTypeDefs[46] = (Constants.Colors.BLOCKSI);
            colorTypeDefs[47] = (Constants.Colors.BLOCKCO);
            colorTypeDefs[48] = (Constants.Colors.SPIKES);
            colorTypeDefs[49] = (Constants.Colors.CANDLEB);
            colorTypeDefs[50] = (Constants.Colors.BOOK);

            colorTypeDefs[51] = (Constants.Colors.WEB);
            colorTypeDefs[52] = (Constants.Colors.VINE);
            colorTypeDefs[53] = (Constants.Colors.SAND);
            colorTypeDefs[54] = (Constants.Colors.GLASS);
            colorTypeDefs[55] = (Constants.Colors.SIGN);
            colorTypeDefs[56] = (Constants.Colors.OBSIDIAN);
            colorTypeDefs[57] = (Constants.Colors.ASH);
            colorTypeDefs[58] = (Constants.Colors.HELLSTONE);
            colorTypeDefs[59] = (Constants.Colors.MUD);
            colorTypeDefs[60] = (Constants.Colors.UNDERGROUNDJUNGLE_GRASS);

            colorTypeDefs[61] = (Constants.Colors.UNDERGROUNDJUNGLE_PLANTS);
            colorTypeDefs[62] = (Constants.Colors.UNDERGROUNDJUNGLE_VINES);
            colorTypeDefs[63] = (Constants.Colors.GEMS_S);
            colorTypeDefs[64] = (Constants.Colors.GEMS_R);
            colorTypeDefs[65] = (Constants.Colors.GEMS_E);
            colorTypeDefs[66] = (Constants.Colors.GEMS_T);
            colorTypeDefs[67] = (Constants.Colors.GEMS_A);
            colorTypeDefs[68] = (Constants.Colors.GEMS_D);
            colorTypeDefs[69] = (Constants.Colors.UNDERGROUNDJUNGLE_THORNS);
            colorTypeDefs[70] = (Constants.Colors.UNDERGROUNDMUSHROOM_GRASS);

            colorTypeDefs[71] = (Constants.Colors.UNDERGROUNDMUSHROOM_PLANTS);
            colorTypeDefs[72] = (Constants.Colors.UNDERGROUNDMUSHROOM_TREES);
            colorTypeDefs[73] = (Constants.Colors.PLANTS);
            colorTypeDefs[74] = (Constants.Colors.PLANTS);
            colorTypeDefs[75] = (Constants.Colors.BLOCKOB);
            colorTypeDefs[76] = (Constants.Colors.BLOCKHS);
            colorTypeDefs[77] = (Constants.Colors.UFURNACE);
            colorTypeDefs[78] = (Constants.Colors.DPOT);
            colorTypeDefs[79] = (Constants.Colors.BED);
            colorTypeDefs[80] = (Constants.Colors.UNKNOWN);

            for (int i = 80; i < 255; i++)
            {
                colorTypeDefs[i] = (Color.Magenta);
            }

            colorTypeDefs[256] = (Constants.Colors.SKY);
            colorTypeDefs[257] = (Constants.Colors.WATER);
            colorTypeDefs[258] = (Constants.Colors.LAVA);

            // Walls
            colorTypeDefs[259] = (Constants.Colors.WALL_STONE);
            colorTypeDefs[260] = (Constants.Colors.WALL_DIRT);
            colorTypeDefs[261] = (Constants.Colors.WALL_STONE2);
            colorTypeDefs[262] = (Constants.Colors.WALL_WOOD);
            colorTypeDefs[263] = (Constants.Colors.WALL_BRICK);
            colorTypeDefs[264] = (Constants.Colors.WALL_BRICKR);
            colorTypeDefs[265] = (Constants.Colors.WALL_BRICKB);
            colorTypeDefs[266] = (Constants.Colors.WALL_BRICKG);
            colorTypeDefs[267] = (Constants.Colors.WALL_BRICKP);
            colorTypeDefs[268] = (Constants.Colors.WALL_BRICKGO);
            colorTypeDefs[269] = (Constants.Colors.WALL_BRICKS);
            colorTypeDefs[270] = (Constants.Colors.WALL_BRICKC);
            colorTypeDefs[271] = (Constants.Colors.WALL_BRICKHS);
            colorTypeDefs[272] = (Constants.Colors.WALL_BACKGROUND);





        }

        public void OpenWorld(string worldPath)
        {
            reader = new WorldReader(worldPath);
            this.worldHeader = reader.ReadHeader();

        }

        public void CreatePreviewPNG(string outputPngPath, bool canDrawWalls, bool canDrawSymbols, ProgressBar progressBar)
        {
            // Reset Symbol List
            tilesToSymbolize = new Dictionary<TileType, List<Point>>();

            int maxX = (int)Header.MaxTiles.Y;
            int maxY = (int)Header.MaxTiles.X;
            //byte[,] pixels = new byte[cols, rows];

            Bitmap bitmap = new Bitmap(maxX, maxY);
            Graphics graphicsHandle = Graphics.FromImage((Image)bitmap);
            graphicsHandle.FillRectangle(new SolidBrush(Constants.Colors.SKY), 0, 0, bitmap.Width, bitmap.Height);

            Dictionary<byte, Color> randomColors = new Dictionary<byte, Color>();
            Random random = new Random();
            TileProperties properties;
            TileType tileType;

            for (int col = 0; col < maxX; col++)
            {
                progressBar.Value = (int)(((float)col / (float)maxX) * 100.0f);
                for (int row = 0; row < maxY; row++)
                {
                    tileType = reader.GetNextTile();
                    if (tileType == TileType.Sky && row > (int)this.Header.SurfaceLevel)
                    {
                        tileType = TileType.WallBackground;
                    }

                    // Skip Walls
                    if (!canDrawWalls && tileType >= TileType.WallStone)
                    {
                        continue;
                    }

                    properties = tileTypeDefs[(int)tileType];

                    if (properties.Symbol != null)
                    {
                        if (!tilesToSymbolize.ContainsKey(tileType))
                        {
                            tilesToSymbolize.Add(tileType, new List<Point>());
                        }
                        tilesToSymbolize[tileType].Add(new Point(col, row));
                        continue;
                    }

                    // Else Set Pixel Value
                    bitmap.SetPixel(col, row, tileTypeDefs[(int)tileType].Colour);
                }
                //reader.GetTheRest();
            }

            // Draw Symbols
            if (canDrawSymbols)
            {
                foreach (KeyValuePair<TileType, List<Point>> kv in tilesToSymbolize)
                {
                    foreach (Point p in kv.Value)
                    {
                        Bitmap symbol = tileTypeDefs[(int)kv.Key].Symbol.BMP;
                        int x = Math.Max((int)p.X - (symbol.Width / 2), 0);
                        int y = Math.Max((int)p.Y - (symbol.Height / 2), 0);
                        graphicsHandle.DrawImage(symbol, x, y);
                    }
                }
            }


            // Spawn
            Bitmap spawnSymbol = new Symbol("spawn.png").BMP;
            int spawnX = Math.Max((int)this.Header.SpawnPoint.X - (spawnSymbol.Width / 2), 0);
            int spawnY = Math.Max((int)this.Header.SpawnPoint.Y - (spawnSymbol.Height / 2), 0);
            if (canDrawSymbols)
            {

                graphicsHandle.DrawImage(spawnSymbol, spawnX, spawnY);
            }
            else
            {
                bitmap.SetPixel(spawnX, spawnY, Constants.Colors.SPAWN);
            }



            bitmap.Save(outputPngPath, ImageFormat.Png);
            progressBar.Value = 100;
        }

        public void CloseWorld()
        {
            reader.Close();
        }

        public void AnalyseWorld(string WorldName, int Number, int id, int spawnX, int spawnY, string output, bool boss1, bool boss2, bool boss3, ProgressBar progressBar, string file, int sLv, int rLv)
        {
            FileStream streamI = new FileStream(file, FileMode.Open);
            Bitmap image = new Bitmap(streamI);
            FileStream stream = new FileStream(output, FileMode.Create);
            writer = new BinaryWriter(stream);
            stream.Seek(0, SeekOrigin.Begin);

            writer.Write((Int32)Number); //Release Number Int32
            writer.Write((string)WorldName); //World Name string
            writer.Write((Int32)id); //Id Int32
            writer.Write((Int32)0); //World Coords Point 1 Int32
            writer.Write((Int32)(image.Width * 16)); //World Coords Point 3 Int32
            writer.Write((Int32)0); //World Coords Point 2 Int32
            writer.Write((Int32)(image.Height * 16)); //World Coords Point 4 Int32
            writer.Write((Int32)image.Height); //Maxtiles X Int32
            writer.Write((Int32)image.Width); //Maxtiles Y Int32
            writer.Write((Int32)spawnX); //SpawnPoint X Int32
            writer.Write((Int32)spawnY); //SpawnPoint Y Int32
            writer.Write((Double)sLv); //SurfaceLevel Double
            writer.Write((Double)rLv); //RockLayer Double
            writer.Write((Double)1); //Temp Time Double
            writer.Write(true); //IsDay bool
            writer.Write((Int32)1); //Moon Phase Int32
            writer.Write(false); //IsBloodMoon bool
            writer.Write((Int32)0); //Dungeon X Int32
            writer.Write((Int32)0); //Dungeon Y Int32
            writer.Write((bool)boss1); //Boss1 Dead bool
            writer.Write((bool)boss2); //Boss2 Dead bool
            writer.Write((bool)boss3); //Boss3 Dead bool
            writer.Write(false); //ShadowOrbSmashed? bool
            writer.Write(false); //IsMetSpawn? bool
            writer.Write((byte)0); //# of orbs smashed byte
            writer.Write((Int32)0); //InvasionDelay Int32
            writer.Write((Int32)0); //InvasionSize Int32
            writer.Write((Int32)0); //InvasionType Int32
            writer.Write((Double)0); //InvationPointX Double


            for (int col = 0; col < image.Width; col++)
            {
                for (int row = 0; row < image.Height; row++)
                {
                    Color pix = image.GetPixel(col, row);
                    int by = Array.FindIndex(colorTypeDefs, element => element.Equals(pix));
                    Color c = Array.Find(colorTypeDefs, element => element.Equals(pix));
                    Block block = new Block();

                    if (pix == Constants.Colors.UNKNOWN || pix == Constants.Colors.UNKNOWN)
                    {
                        block.Tilebyte = 0;
                    }

                    if (pix == Constants.Colors.WATER)
                    {
                        block.liquid = true;
                    }
                    if (pix == Constants.Colors.LAVA)
                    {
                        block.liquid = true;
                        block.lava = true;
                        block.light = true;
                    }

                    Color[] Light = { Constants.Colors.CANDLE, Constants.Colors.CANDLEB, Constants.Colors.FURNACE, Constants.Colors.HELLSTONE, Constants.Colors.METEORITE, Constants.Colors.SORB, Constants.Colors.UFURNACE };
                    if (Array.Exists(Light, elements => elements.Equals(pix)))
                    {
                        block.light = true;
                    }
                    bool active = true;
                    Color[] Wall = { Constants.Colors.WALL_BACKGROUND, Constants.Colors.WALL_BRICK, Constants.Colors.WALL_BRICKB, Constants.Colors.WALL_BRICKC, Constants.Colors.WALL_BRICKG, Constants.Colors.WALL_BRICKGO, Constants.Colors.WALL_BRICKHS, Constants.Colors.WALL_BRICKP, Constants.Colors.WALL_BRICKR, Constants.Colors.WALL_BRICKS, Constants.Colors.WALL_DIRT, Constants.Colors.WALL_STONE, Constants.Colors.WALL_STONE2, Constants.Colors.WALL_WOOD };
                    if (Array.Exists(Wall, elements => elements.Equals(pix)))
                    {
                        block.wall = true;
                        active = false;
                        by -= Constants.WallOffset;
                    }
                    string pixS = pix.ToString();
                    pixS = pixS.ToLower();

                    if (pix == Constants.Colors.SKY || pix == Constants.Colors.LAVA || pix == Constants.Colors.WATER)
                    {
                        active = false;
                    }

                    if (by < 0)
                    {
                        active = false;
                        by = 0;
                    }
                    block.Tilebyte = (byte)by;

                    if (pix != Constants.Colors.SPAWN)
                    {
                        writer.Write(active);
                        if (active)
                        {

                            writer.Write(block.Tilebyte);


                            if (WorldMapper.tileTypeDefs[block.Tilebyte].IsImportant)
                            {

                                writer.Write((Int16)0);
                                writer.Write((Int16)0);
                            }

                        }
                        writer.Write(false);
                        writer.Write(block.wall);
                        if (block.isWall)
                        {
                            writer.Write((byte)block.Tilebyte);
                        }
                        writer.Write(block.liquid);
                        if (block.isLiquid)
                        {
                            writer.Write(block.level);
                            writer.Write(block.lava);
                        }
                    }
                    progressBar.Value = (int)(((float)col / (float)image.Width) * 100.0f);
                    //System.Diagnostics.Debug.WriteLine(progressBar.Value);
                }
            }
            for (int i = 0; i < 5000; i++)
            {
                writer.Write(false);
            }
            progressBar.Value = 100;
            writer.Close();
            stream.Close();
            streamI.Close();
        }

        /*
        public void CreateWorld(string WorldName, int Number, int id, int spawnX, int spawnY, string output, bool boss1,bool boss2,bool boss3,int h, int w,int spX, int spY,int sLv, int rLv)
        {
            FileStream stream = new FileStream(output, FileMode.Create);
            writer = new BinaryWriter(stream);
            stream.Seek(0, SeekOrigin.Begin);

            if (spawnX == 0 && spawnY == 0)
            {
                spawnX = spX;
                spawnY = spY;
            }

            //World Header
            /*writer.Write((Int32)Number); //Release Number Int32
            writer.Write((string)WorldName); //World Name string
            writer.Write((Int32)id); //Id Int32
            Write7BitEncodedInt(writer, (Int32)0); //World Coords Point 1 Int32
            Write7BitEncodedInt(writer, (Int32)0); //World Coords Point 2 Int32
            Write7BitEncodedInt(writer, (Int32)(w * 16)); //World Coords Point 3 Int32
            Write7BitEncodedInt(writer, (Int32)(h * 16)); //World Coords Point 4 Int32
            Write7BitEncodedInt(writer, (Int32)h); //Maxtiles X Int32
            Write7BitEncodedInt(writer, (Int32)w); //Maxtiles Y Int32
            Write7BitEncodedInt(writer, (Int32)spawnX); //SpawnPoint X Int32
            Write7BitEncodedInt(writer, (Int32)spawnY); //SpawnPoint Y Int32
            writer.Write((Double)0); //SurfaceLevel Double
            writer.Write((Double)0); //RockLayer Double
            writer.Write((Double)1); //Temp Time Double
            writer.Write(true); //IsDay bool
            Write7BitEncodedInt(writer, (Int32)1); //Moon Phase Int32
            writer.Write(false); //IsBloodMoon bool
            Write7BitEncodedInt(writer, (Int32)0); //Dungeon X Int32
            Write7BitEncodedInt(writer, (Int32)0); //Dungeon Y Int32
            writer.Write((bool)boss1); //Boss1 Dead bool
            writer.Write((bool)boss2); //Boss2 Dead bool
            writer.Write((bool)boss3); //Boss3 Dead bool
            writer.Write(false); //ShadowOrbSmashed? bool
            writer.Write(false); //IsMetSpawn? bool
            writer.Write((byte)0); //# of orbs smashed byte
            Write7BitEncodedInt(writer, (Int32)0); //InvasionDelay Int32
            Write7BitEncodedInt(writer, (Int32)0); //InvasionSize Int32
            Write7BitEncodedInt(writer, (Int32)0); //InvasionType Int32
            writer.Write((Double)0); //InvationPointX Double

            writer.Write((Int32)Number); //Release Number Int32
            writer.Write((string)WorldName); //World Name string
            writer.Write((Int32)id); //Id Int32
            writer.Write((Int32)0); //World Coords Point 1 Int32
            writer.Write((Int32)(w * 16)); //World Coords Point 3 Int32
            writer.Write((Int32)0); //World Coords Point 2 Int32
            writer.Write((Int32)(h * 16)); //World Coords Point 4 Int32
            writer.Write((Int32)h); //Maxtiles X Int32
            writer.Write((Int32)w); //Maxtiles Y Int32
            writer.Write((Int32)spawnX); //SpawnPoint X Int32
            writer.Write((Int32)spawnY); //SpawnPoint Y Int32
            writer.Write((Double)sLv); //SurfaceLevel Double
            writer.Write((Double)rLv); //RockLayer Double
            writer.Write((Double)1); //Temp Time Double
            writer.Write(true); //IsDay bool
            writer.Write((Int32)1); //Moon Phase Int32
            writer.Write(false); //IsBloodMoon bool
            writer.Write((Int32)0); //Dungeon X Int32
            writer.Write((Int32)0); //Dungeon Y Int32
            writer.Write((bool)boss1); //Boss1 Dead bool
            writer.Write((bool)boss2); //Boss2 Dead bool
            writer.Write((bool)boss3); //Boss3 Dead bool
            writer.Write(false); //ShadowOrbSmashed? bool
            writer.Write(false); //IsMetSpawn? bool
            writer.Write((byte)0); //# of orbs smashed byte
            writer.Write((Int32)0); //InvasionDelay Int32
            writer.Write((Int32)0); //InvasionSize Int32
            writer.Write((Int32)0); //InvasionType Int32
            writer.Write((Double)0); //InvationPointX Double

            byte[] bytes = { 0, 0, 0, 1 };
            
            writer.Write(true);
            for (int i = 0; i < 600; i++)
            {
                writer.Write(0x00);
            }
            //Close the streams
            writer.Close();
            stream.Close();
        }
         * */
        protected static void Write7BitEncodedInt(BinaryWriter bin, int value)
        {
            uint num = (uint)value;
            while (num >= 0x80)
            {
                bin.Write((byte)(num | 0x80));
                num = num >> 7;
            }
            bin.Write((byte)num);
        }

        public void CreateReference()
        {
            string Filename = "";
            SaveFileDialog dialogW = new SaveFileDialog();
            dialogW.Filter = "Terraria Reference File (*.png)|*.png";
            dialogW.Title = "Select Reference File";
            dialogW.FileName = string.Format("{0}.png", System.IO.Path.GetFileNameWithoutExtension(Filename));
            string filePath = (dialogW.ShowDialog() == DialogResult.OK) ? dialogW.FileName : string.Empty;
            if (filePath == string.Empty)
            {
                return;
            }
            else if (new System.IO.FileInfo(filePath).Extension.ToUpper() != ".PNG")
            {
                MessageBox.Show("Reference File MUST End in .png", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            Bitmap refI = new Bitmap(500, (colorTypeDefs.Length - (255 - 80)) * 25);
            Graphics g = Graphics.FromImage((Image)refI);
            int i = 0;
            foreach (Color c in colorTypeDefs)
            {
                if (i < 80 || i > 255)
                {
                    SolidBrush s = new SolidBrush(c);
                    string Name = "Unknown";
                    try
                    {
                        Name = tileTypeDefs[i].TileType.ToString();
                    }
                    catch (KeyNotFoundException e)
                    {
                    }
                    int r = i;
                    if (r > 80)
                    {
                        r -= (255 - 80);
                    }
                    g.DrawString(Name, new Font("Times New Roman", 20), s, new Rectangle(0, r * 25, 500, 50));
                }
                    i++;
            }
            refI.Save(filePath);
        }

    }
}
